﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Xml.Linq;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;

namespace Qianke.Core.Common.NameMutex
{
    public class LocalNameMutex : INameMutex,ITransientDependency
    {
        /// <summary>
        /// 互斥体信息  用户记录多次获取锁到情况
        /// </summary>
        class MutexInfo
        {
            public SemaphoreSlim hMutex { set; get; }

            public int UserCount { set; get; }

            public List<INameMutex> nameMutexes { set; get; }
        }

        private static Dictionary<string, MutexInfo> MutexDict = new Dictionary<string, MutexInfo>();

        private SemaphoreSlim _hMutex;


        private string _KeyName { set; get; }



        public Task EnterAsync()
        {
            return _hMutex.WaitAsync();
        }

        public Task ExitAsync()
        {
            if (_hMutex != null)
            {
                _hMutex.Release();
                lock (MutexDict)
                {
                    if (MutexDict.ContainsKey(_KeyName))
                    {
                        var dict = MutexDict[_KeyName];
                        dict.UserCount--;
                        if (dict.UserCount == 0)
                            MutexDict.Remove(_KeyName);
                        else
                            dict.nameMutexes.Remove(this);
                    }
                }
            }
            _hMutex = null;
            return Task.CompletedTask;
        }



        public Task InitializeAsync(string mutexName)
        {
            _KeyName = mutexName;
            lock (MutexDict)
            {
                if (MutexDict.ContainsKey(_KeyName))
                {
                    var obj = MutexDict[_KeyName];
                    _hMutex = obj.hMutex;
                    obj.UserCount++;
                    obj.nameMutexes.Add(this);
                }
                else
                {
                    _hMutex = new SemaphoreSlim(1);
                    MutexDict.Add(_KeyName, new MutexInfo()
                    {
                        hMutex = _hMutex,
                        UserCount = 1,
                        nameMutexes = new List<INameMutex>() { this }
                    });
                }
            }
            return Task.CompletedTask;
        }



        public async ValueTask DisposeAsync()
        {
            await ExitAsync();
        }

        public void Dispose()
        {
            _ = Task.Run(() => this.DisposeAsync());
        }
    }
}
